#include <x86intrin.h>
#include <stdio.h>
#include <complex>
#include <iostream>
#include <chrono>
// #include <mkl.h>
// #include <omp.h>
typedef std::chrono::high_resolution_clock Clock;
using namespace std;

#define NN 10000000
alignas(32) double tmp_d24[24];
alignas(32) complex<double> tmp_c12[12];
const complex<double> Ihalf(0, 0.5);
const complex<double> Ihalfn(0, -0.5);
inline void cal_t_f(complex<double> *srcO, complex<double> *AE, complex<double> *destE, double flag,
                    complex<double> I)
{
    std::complex<double> tmp;
    const double half = 0.5;
    for (int c1 = 0; c1 < 3; c1++) {
        for (int c2 = 0; c2 < 3; c2++) {
            tmp = -(srcO[0 * 3 + c2] - flag * srcO[2 * 3 + c2]) * half * AE[c1 * 3 + c2];
            destE[0 * 3 + c1] += tmp;
            destE[2 * 3 + c1] -= flag * (tmp);
            tmp = -(srcO[1 * 3 + c2] - flag * srcO[3 * 3 + c2]) * half * AE[c1 * 3 + c2];
            destE[1 * 3 + c1] += tmp;
            destE[3 * 3 + c1] -= flag * (tmp);
        }
    }
}

inline void cal_t_f2(complex<double> *srcO, complex<double> *AE, complex<double> *destE,
                     double flag, complex<double> I)
{
    std::complex<double> tmp;
    const double half = 0.5;

    const double *dsrcO = (const double *) srcO;
    double* ddest = (double*) destE;
    // double* dAE = (double*) AE;
    // complex x0 x1 x2
    tmp_d24[0] = (dsrcO[0] - dsrcO[9 * 2 + 1]);
    tmp_d24[1] = (dsrcO[1] - dsrcO[9 * 2]);
    tmp_d24[2] = (dsrcO[2] - dsrcO[10 * 2 + 1]);
    tmp_d24[3] = (dsrcO[3] - dsrcO[10 * 2]);
    tmp_d24[4] = (dsrcO[4] - dsrcO[11 * 2 + 1]);
    tmp_d24[5] = (dsrcO[5] - dsrcO[11 * 2]);
    // complex x3 x4 x5
    tmp_d24[6] = (dsrcO[6] - dsrcO[6 * 2 + 1]);
    tmp_d24[7] = (dsrcO[7] - dsrcO[6 * 2]);
    tmp_d24[8] = (dsrcO[8] - dsrcO[7 * 2 + 1]);
    tmp_d24[9] = (dsrcO[9] - dsrcO[7 * 2]);
    tmp_d24[10] = (dsrcO[10] - dsrcO[8 * 2 + 1]);
    tmp_d24[11] = (dsrcO[11] - dsrcO[8 * 2]);

    complex<double> *ctmp_d24 = (complex<double> *) tmp_d24;

    tmp_c12[0] = (ctmp_d24[0] * AE[0] + ctmp_d24[1] * AE[1] + ctmp_d24[2] * AE[2]);
    tmp_c12[1] = (ctmp_d24[0] * AE[3] + ctmp_d24[1] * AE[4] + ctmp_d24[2] * AE[5]);
    tmp_c12[2] = (ctmp_d24[0] * AE[6] + ctmp_d24[1] * AE[7] + ctmp_d24[2] * AE[8]);
    tmp_c12[3] = (ctmp_d24[3] * AE[0] + ctmp_d24[4] * AE[1] + ctmp_d24[5] * AE[2]);
    tmp_c12[4] = (ctmp_d24[3] * AE[3] + ctmp_d24[4] * AE[4] + ctmp_d24[5] * AE[5]);
    tmp_c12[5] = (ctmp_d24[3] * AE[6] + ctmp_d24[4] * AE[7] + ctmp_d24[5] * AE[8]);

    for (size_t i = 0; i < 6; i++)
        destE[i] += -0.5 * tmp_c12[i];
    for (size_t i = 0; i < 3; i++)
        destE[i + 6] += flag * Ihalfn * tmp_c12[i + 3];
    for (size_t i = 0; i < 3; i++)
        destE[i + 9] += flag * Ihalfn * tmp_c12[i];

    // for (int c1 = 0; c1 < 3; c1++) {
    //     for (int c2 = 0; c2 < 3; c2++) {
    //         tmp = -(srcO[0 * 3 + c2] - flag * srcO[2 * 3 + c2]) * half * AE[c1 * 3 + c2];
    //         destE[0 * 3 + c1] += tmp;
    //         destE[2 * 3 + c1] -= flag * (tmp);
    //         tmp = -(srcO[1 * 3 + c2] - flag * srcO[3 * 3 + c2]) * half * AE[c1 * 3 + c2];
    //         destE[1 * 3 + c1] += tmp;
    //         destE[3 * 3 + c1] -= flag * (tmp);
    //     }
    // }
}

int main()
{
    complex<double> *srcO = new complex<double>[NN * 12];
    complex<double> *dest = new complex<double>[NN * 12];
    complex<double> *U = new complex<double>[NN * 9];
    double flag = 1;
    complex<double> I = {0, 1};
    auto startTime = Clock::now();

    for (int i = 0; i < NN; i++) {
        cal_t_f2(srcO + i * 12, U + i * 9, dest + i * 12, flag, I);
    }

    auto endTime = Clock::now();
    auto compTime0 = chrono::duration_cast<chrono::microseconds>(endTime - startTime);
    cout << compTime0.count() / 1000.0 << endl;

    delete[] srcO;
    delete[] dest;
    delete[] U;
}